package cn.demoncat.util.redis.util;

import cn.demoncat.util.redis.config.RedisIsolator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;

/**
 * Redis 脚本执行工具
 *
 * @author 延晓磊
 * @since 2021年02月13日
 */
@Component
public class RedisExecuteUtil {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisIsolator redisIsolator;

    /**
     * 执行脚本
     *
     * 1、减少网络开销：在Lua脚本中同时执行多条命令
     * 2、原子操作：Redis会将整个脚本作为一个整体执行，中间不会被其他命令插入
     * 3、流程控制：可以添加流程和判断控制
     *
     * 语法：EVAL "脚本" 1 key val...
     * 命令：在脚本中，可以通过 redis.call('DEL',KEYS[1]) 的方式调用Redis命令
     * 取值：在脚本中，可以通过 KEYS[1] 获取key参数，通过 ARGV[1] ARGV[2] 获取val参数
     *
     * @param clazz		返回类型：数值 long，布尔 boolean，字符串 String
     * @param script	LUA脚本
     * @param key		KEY
     * @param args		参数
     *
     * @author 延晓磊
     * @since 2021年02月08日
     *
     * @see <a href="https://www.runoob.com/lua/lua-tutorial.html">LUA</a>
     */
    public <R>R execute(Class<R> clazz, String script, String key, Object ... args){
        return stringRedisTemplate.execute(new DefaultRedisScript<>(script,clazz), Collections.singletonList(redisIsolator.getKey(key)), args);
    }

    /**
     * 执行脚本 - 无返回
     *
     * @param script	LUA脚本
     * @param key		KEY
     * @param args		参数
     *
     * @author 延晓磊
     * @since 2021年02月08日
     */
    public void execute(String script, String key, Object ... args){
        stringRedisTemplate.execute(new DefaultRedisScript<>(script), Collections.singletonList(redisIsolator.getKey(key)), args);
    }
}
